home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / roff < prev    next >
Encoding:
Text File  |  1992-01-03  |  30.3 KB  |  1,591 lines

  1. Newsgroups: comp.sources.unix
  2. From: gls@cbnewsh.att.com (Col. G. L. Sicherman)
  3. Subject: v25i091: roff - simple text formatter
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: gls@cbnewsh.att.com (Col. G. L. Sicherman)
  8. Posting-Number: Volume 25, Issue 91
  9. Archive-Name: roff
  10.  
  11. [ I'm posting this because people keep asking for it.
  12.   It's essentially the same as the version in MINIX.
  13.                         --gls ]
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of shell archive."
  22. # Contents:  roff.1 roff.c Makefile
  23. # Wrapped by vixie@cognition.pa.dec.com on Fri Jan  3 17:49:57 1992
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'roff.1' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'roff.1'\"
  27. else
  28. echo shar: Extracting \"'roff.1'\" \(6693 characters\)
  29. sed "s/^X//" >'roff.1' <<'END_OF_FILE'
  30. X.TH ROFF 1 "19 May 1983"
  31. X.SH NAME
  32. roff \- format text
  33. X.SH SYNOPSIS
  34. X.B \*(Bd/roff
  35. X[ \fB+\fIn\fR ] [ \fB\-\fIn\fR ] [
  36. X.B \-s
  37. X] [
  38. X.B \-h
  39. X] file ...
  40. X.PP
  41. X.B nroff \-mr
  42. X[ option ] ... file ...
  43. X.br
  44. X.B troff \-mr
  45. X[ option ] ... file ...
  46. X.SH DESCRIPTION
  47. X.I Roff
  48. formats text according to control lines embedded
  49. in the text in the given files.
  50. XEncountering a nonexistent file terminates printing.
  51. Incoming inter-terminal messages are turned off during printing.
  52. The optional flag arguments mean:
  53. X.br
  54. X.ns
  55. X.TP 5
  56. X.BI + n
  57. Start printing at the first page with number
  58. X.IR n .
  59. X.br
  60. X.ns
  61. X.TP 5
  62. X.BI \- n
  63. Stop printing at the first page numbered higher
  64. than
  65. X.IR n .
  66. X.br
  67. X.ns
  68. X.TP 5
  69. X.B \-s
  70. Stop before each page (including the first)
  71. to allow paper manipulation;
  72. resume on receipt of an interrupt signal.
  73. X.br
  74. X.ns
  75. X.TP 5
  76. X.B \-h
  77. Insert tabs in the output stream to replace
  78. spaces whenever appropriate.
  79. X.PP
  80. X.DT
  81. Input consists of intermixed
  82. X.I "text lines,"
  83. which contain information to be formatted, and
  84. X.I "request lines,"
  85. which contain instructions about how to format
  86. it.
  87. Request lines begin with a distinguished
  88. X.I "control character,"
  89. normally a period.
  90. X.PP
  91. Output lines may be
  92. X.I filled
  93. as nearly as possible with words without regard to
  94. input lineation.
  95. Line
  96. X.I breaks
  97. may be caused at specified places by
  98. certain commands, or by the appearance of an
  99. empty input line or an input line beginning with a space.
  100. X.PP
  101. The capabilities of
  102. X.I roff
  103. are specified in the attached Request Summary.
  104. Numerical values are denoted there by n or +n,
  105. titles by t, and single characters by c.
  106. Numbers denoted +n may be signed + or \-,
  107. in which case they signify relative changes to
  108. a quantity, otherwise they signify
  109. an absolute resetting.
  110. Missing n fields are ordinarily taken to be 1,
  111. missing t fields to be empty, and c fields to shut off
  112. the appropriate special interpretation.
  113. X.PP
  114. Running titles usually appear at top and bottom of every
  115. page.
  116. They are set by requests like
  117. X.PP
  118. X.in +10
  119. X.if t \&.he \(fmpart1\(fmpart2\(fmpart3\(fm
  120. X.if n \&.he 'part1'part2'part3'
  121. X.in -10
  122. X.PP
  123. Part1 is left justified, part2 is centered,
  124. and part3 is right justified on the page.
  125. Any % sign in a title is replaced by the current
  126. page number.
  127. Any nonblank may serve as a quote.
  128. X.PP
  129. ASCII tab characters are replaced in the input by a
  130. X.I "replacement character,"
  131. normally a space,
  132. according to the
  133. column settings given by a .ta command.
  134. X(See .tr for how to convert this character on output.)
  135. X.PP
  136. Automatic hyphenation of filled output is done
  137. under control of .hy.
  138. When a word contains a designated
  139. X.I "hyphenation character,"
  140. that character disappears from the output and
  141. hyphens can be introduced into
  142. the word at the marked places only.
  143. X.PP
  144. The
  145. X.B \-mr
  146. option of
  147. X.I nroff
  148. or 
  149. X.IR troff (1)
  150. simulates
  151. X.I roff
  152. to the greatest extent possible.
  153. X.SH FILES
  154. X.\" /usr/lib/suftab    suffix hyphenation tables
  155. X.\" .br
  156. X/tmp/rtm*    temporary
  157. X.br
  158. X.SH BUGS
  159. X.I Roff
  160. is the simplest of the text formatting
  161. programs, and is utterly frozen.
  162. X.PP
  163. This is a home-brewed C version of a V7 assembly-language program.
  164. It hyphenates only at hyphenation characters
  165. and comes with no guarantees.
  166. In particular, ridiculously long source lines will crash it.
  167. X.SH AUTHOR
  168. G. L. Sicherman (decvax!sunybcs!colonel)
  169. X.bp
  170. X.tc |
  171. X.tr |
  172. X.in 0
  173. X.ce
  174. REQUEST SUMMARY
  175. X.\"    V7 man page used .li, which is not available in ditroff.
  176. X.\"    Use \& throughout instead.    --the Col.
  177. X.\".PP
  178. X.ul
  179. X.ta \w'.tr cdef.. 'u +\w'Break 'u +\w'Initial 'u
  180. X.di x
  181. X            \ka
  182. X.br
  183. X.di
  184. X.in \nau
  185. X.ti 0
  186. Request    Break    Initial    Meaning
  187. X.na
  188. X.ti 0
  189. X\&.ad    yes    yes    Begin adjusting right margins.
  190. X.ti 0
  191. X\&.ar    no    arabic    Arabic page numbers.
  192. X.ti 0
  193. X\&.br    yes    \-    Causes a line break \- the filling of
  194. the current line is stopped.
  195. X.ti 0
  196. X\&.bl|n    yes    \-    Insert of n blank lines, on new page if necessary.
  197. X.ti 0
  198. X\&.bp|+n    yes    n=1    Begin new page and number it n; no n means `+1'.
  199. X.ti 0
  200. X\&.cc|c    no    c=.    Control character becomes `c'.
  201. X.ti 0
  202. X\&.ce|n    yes    \-    Center the next n input lines,
  203. without filling.
  204. X.ti 0
  205. X\&.de|xx    no    \-    Define parameterless macro 
  206. to be invoked by request `.xx'
  207. X(definition ends on line beginning `\fB..\fR').
  208. X.ti 0
  209. X\&.ds    yes    no    Double space; same as `.ls 2'.
  210. X.ti 0
  211. X\&.ef|t    no    t=\*a\*a\*a\*a    Even foot title becomes t.
  212. X.ti 0
  213. X\&.eh|t    no    t=\*a\*a\*a\*a    Even head title becomes t.
  214. X.ti 0
  215. X\&.fi    yes    yes    Begin filling output lines.
  216. X.ti 0
  217. X\&.fo    no    t=\*a\*a\*a\*a    All foot titles are t.
  218. X.ti 0
  219. X\&.hc|c    no    none    Hyphenation character becomes `c'.
  220. X.ti 0
  221. X\&.he|t    no    t=\*a\*a\*a\*a    All head titles are t.
  222. X.ti 0
  223. X\&.hx    no    \-    Title lines are suppressed.
  224. X.ti 0
  225. X\&.hy|n    no    n=1    Hyphenation is done, if n=1;
  226. and is not done, if n=0.
  227. X.ti 0
  228. X\&.ig    no    \-    Ignore input lines through
  229. a line beginning with `\fB..\fR'.
  230. X.ti 0
  231. X\&.in|+n    yes    \-    Indent n spaces from left margin.
  232. X.ti 0
  233. X\&.ix +n    no    \-    Same as `.in' but without break.
  234. X.ti 0
  235. X\&.li|n    no    \-    Literal, treat next n lines as text.
  236. X.ti 0
  237. X\&.ll|+n    no    n=65    Line length including indent is n characters.
  238. X.ti 0
  239. X\&.ls|+n    yes    n=1    Line spacing set to n lines per output line.
  240. X.ti 0
  241. X\&.m1|n    no    n=2    Put n blank lines between the top
  242. of page and head title.
  243. X.ti 0
  244. X\&.m2|n    no    n=2    n blank lines put between head title
  245. and beginning of text on page.
  246. X.ti 0
  247. X\&.m3|n    no    n=1    n blank lines put between end of
  248. text and foot title.
  249. X.ti 0
  250. X\&.m4|n    no    n=3    n blank lines put between the foot title
  251. and the bottom of page.
  252. X.ti 0
  253. X\&.na    yes    no    Stop adjusting the right margin.
  254. X.ti 0
  255. X\&.ne|n    no    \-    Begin new page, if n output lines
  256. cannot fit on present page.
  257. X.ti 0
  258. X\&.nn|+n    no    \-    The next n output lines are not numbered.
  259. X.ti 0
  260. X\&.n1    no    no    Add 5 to page offset;
  261. number lines in margin from 1 on each page.
  262. X.ti 0
  263. X\&.n2|n    no    no    Add 5 to page offset;
  264. number lines from n;
  265. stop if n=0.
  266. X.ti 0
  267. X\&.ni|+n    no    n=0    Line numbers are indented n.
  268. X.ti 0
  269. X\&.nf    yes    no    Stop filling output lines.
  270. X.ti 0
  271. X\&.nx|file    no    \-    Switch input to `file'.
  272. X.ti 0
  273. X\&.of|t    no    t=\*a\*a\*a\*a    Odd foot title becomes t.
  274. X.ti 0
  275. X\&.oh|t    no    t=\*a\*a\*a\*a    Odd head title becomes t.
  276. X.ti 0
  277. X\&.pa|+n    yes    n=1    Same as `.bp'.
  278. X.ti 0
  279. X\&.pl|+n    no    n=66    Total paper length taken to be n lines.
  280. X.ti 0
  281. X\&.po|+n    no    n=0    Page offset.
  282. All lines are preceded by n spaces.
  283. X.ti 0
  284. X\&.ro    no    arabic    Roman page numbers.
  285. X.ti 0
  286. X\&.sk|n    no    \-    Produce n blank pages starting next page.
  287. X.ti 0
  288. X\&.sp|n    yes    \-    Insert block of n blank lines,
  289. except at top of page.
  290. X.ti 0
  291. X\&.ss    yes    yes    Single space output lines,
  292. equivalent to `.ls 1'.
  293. X.ti 0
  294. X\&.ta|n|n..        \-    Pseudotab settings.
  295. Initial tab settings are columns 9 17 25 ...
  296. X.ti 0
  297. X\&.tc|c    no    space    Tab replacement character becomes `c'.
  298. X.ti 0
  299. X\&.ti|+n    yes    \-    Temporarily indent next output
  300. line n spaces.
  301. X.ti0
  302. X\&.tr|cdef..    no    \-    Translate c into d, e into f, etc.
  303. X.ti0
  304. X\&.ul|n    no    \-    Underline the letters and numbers
  305. in the next n input lines.
  306. X.br
  307. X.tr ||
  308. END_OF_FILE
  309. if test 6693 -ne `wc -c <'roff.1'`; then
  310.     echo shar: \"'roff.1'\" unpacked with wrong size!
  311. fi
  312. # end of 'roff.1'
  313. fi
  314. if test -f 'roff.c' -a "${1}" != "-c" ; then 
  315.   echo shar: Will not clobber existing file \"'roff.c'\"
  316. else
  317. echo shar: Extracting \"'roff.c'\" \(20604 characters\)
  318. sed "s/^X//" >'roff.c' <<'END_OF_FILE'
  319. X/*
  320. X *    roff - C version.
  321. X *    the Colonel.  19 May 1983.
  322. X *
  323. X *    Copyright 1983 by G. L. Sicherman.
  324. X *    You may use and alter this software freely for noncommercial ends
  325. X *    so long as you leave this message alone.
  326. X *
  327. X *    Fix by Tim Maroney, 31 Dec 1984.
  328. X *    .hc implemented, 8 Feb 1985.
  329. X *    Fix to hyphenating with underlining, 12 Feb 1985.
  330. X *    Fixes to long-line hang and .bp by Dave Tutelman, 30 Mar 1985.
  331. X *    Fix to centering valve with long input lines, 4 May 1987.
  332. X */
  333. X
  334. X#include <sgtty.h>
  335. X#include <signal.h>
  336. X#include <stdio.h>
  337. X#include <sys/types.h>
  338. X#include <sys/stat.h>
  339. X
  340. X/*    MAXMAC - maximum number of macros.    */
  341. X#define MAXMAC    64
  342. X/*    MAXDEPTH - maximum recursion of macros.    */
  343. X#define MAXDEPTH 10
  344. X#define MAXLENGTH 255
  345. X#define UNDERL    '\200'
  346. X#define SUFTAB    "/usr/lib/suftab"
  347. X#define TXTLEN    (o_pl-o_m1-o_m2-o_m3-o_m4-2)
  348. X#define IDTLEN    (o_ti>=0?o_ti:o_in)
  349. X
  350. char spacechars[] = " \t\n";
  351. int sflag, hflag, startpage, stoppage;
  352. char holdword[MAXLENGTH], *holdp;
  353. char assyline[MAXLENGTH];
  354. int assylen;
  355. char ehead[100], efoot[100], ohead[100], ofoot[100];
  356. struct macrotype {
  357. X    char mname[3];
  358. X    long int moff;
  359. X} macro[MAXMAC];
  360. int n_macros;
  361. int depth;
  362. int adjtoggle;
  363. int isrequest = 0;
  364. char o_tr[40][2];    /* OUTPUT TRANSLATION TABLE */
  365. int o_cc = '.';    /* CONTROL CHARACTER */
  366. int o_hc = -1;    /* HYPHENATION CHARACTER */
  367. int o_tc = ' ';    /* TABULATION CHARACTER */
  368. int o_in = 0;    /* INDENT SIZE */
  369. int o_ix = -1;    /* NEXT INDENT SIZE */
  370. int o_ta[20] = {
  371. X    9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 
  372. X    113, 121, 129, 137, 145, 153, 161};
  373. int n_ta = 20;    /* #TAB STOPS */
  374. int o_ll = 65, o_ad = 1, o_po = 0, o_ls = 1, o_ig = 0, o_fi = 1;
  375. int o_pl = 66, o_ro = 0, o_hx = 0, o_bl = 0, o_sp = 0, o_sk = 0;
  376. int o_ce = 0, o_m1 = 2, o_m2 = 2, o_m3 = 1, o_m4 = 3, o_ul = 0;
  377. int o_li = 0, o_n1 = 0, o_n2 = 0, o_bp = -1, o_hy = 1;
  378. int o_ni = 1;    /* LINE-NUMBER INDENT */
  379. int o_nn = 0;    /* #LINES TO SUPPRESS NUMBERING */
  380. int o_ti = -1;    /* TEMPORARY INDENT */
  381. int page_no = -1;
  382. int line_no = 9999;
  383. int n_outwords;
  384. XFILE *File, *Macread, *Macwrite;
  385. XFILE *Save;
  386. long int teller[MAXDEPTH], ftell();
  387. char *strcat(), *strcpy(), *strend(), *strhas();
  388. char *sprintf();
  389. char *request[] = {
  390. X    "ad","ar","bl","bp","br","cc","ce","de",
  391. X    "ds","ef","eh","fi","fo","hc","he","hx","hy","ig",
  392. X    "in","ix","li","ll","ls","m1","m2","m3","m4",
  393. X    "n1","n2","na","ne","nf","ni","nn","nx","of","oh",
  394. X    "pa","pl","po","ro","sk","sp","ss","ta","tc","ti",
  395. X    "tr","ul",0};
  396. char *mktemp(), *mfilnam = "/tmp/rtmXXXXXX";
  397. int c;        /* LAST CHAR READ */
  398. struct sgttyb tty;
  399. X
  400. main(argc,argv)
  401. int argc;
  402. char **argv;
  403. X{
  404. X    while (--argc) switch (**++argv) {
  405. X    case '+':
  406. X        startpage=atoi(++*argv);
  407. X        break;
  408. X    case '-':
  409. X        ++*argv;
  410. X        if (isdigit(**argv)) stoppage=atoi(*argv);
  411. X        else switch(**argv) {
  412. X        case 's':
  413. X            sflag++;
  414. X            break;
  415. X        case 'h':
  416. X            hflag++;
  417. X            break;
  418. X        default:
  419. X            bomb();
  420. X        }
  421. X        break;
  422. X    default:
  423. X        argc++;
  424. X        goto endargs;
  425. X    }
  426. endargs:
  427. X    if (sflag) gtty(0,&tty);
  428. X    mesg(0);    /* BLOCK OUT MESSAGES */
  429. X    assylen=0;
  430. X    assyline[0]='\0';
  431. X    if (!argc) {
  432. X        File=stdin;
  433. X        readfile();
  434. X    }
  435. X    else while (--argc) {
  436. X        File=fopen(*argv,"r");
  437. X        if (NULL==File) {
  438. X            fprintf(stderr,"roff: cannot read %s\n",*argv);
  439. X            exit(1);
  440. X        }
  441. X        readfile();
  442. X        fclose(File);
  443. X        argv++;
  444. X    }
  445. X    writebreak();            /* TERMINATE PARTIAL OUTPUT LINE */
  446. X    endpage();            /* FLUSH LAST PAGE */
  447. X    for (; o_sk; o_sk--) blankpage();    /* FLUSH BLANK PAGES */
  448. X    mesg(1);            /* ALLOW MESSAGES */
  449. X}
  450. X
  451. mesg(f)
  452. int f;
  453. X{
  454. X    static int mode;
  455. X    struct stat cbuf;
  456. X    char *ttyname();
  457. X
  458. X    if (!isatty(1)) return;
  459. X    if (!f) {
  460. X        fstat(1,&cbuf);
  461. X        mode = cbuf.st_mode;
  462. X        chmod(ttyname(1),mode & ~022);
  463. X    }
  464. X    else chmod(ttyname(1),mode);
  465. X}
  466. X
  467. readfile()
  468. X{
  469. X    while (readline()) {
  470. X        if (isrequest) continue;
  471. X        if (o_ce || !o_fi) {
  472. X            if (assylen) writeline(0,1);
  473. X            else blankline();
  474. X            if (o_ce) o_ce--;
  475. X        }
  476. X    }
  477. X}
  478. X
  479. readline()
  480. X{
  481. X    int startline, doingword;
  482. X    isrequest = 0;
  483. X    startline = 1;
  484. X    doingword = 0;
  485. X    c=suck();
  486. X    if (c == '\n') {
  487. X        o_sp = 1;
  488. X        writebreak();
  489. X        goto out;
  490. X    }
  491. X    else if (isspace(c)) writebreak();
  492. X    for (;;) {
  493. X        if (c==EOF) {        /* EOF - FLUSH WORD, IF ANY */
  494. X            if (doingword) bumpword();
  495. X            break;
  496. X        }
  497. X        if (c!=o_cc && o_ig) {    /* IGNORE A TEXT LINE */
  498. X            while (c!='\n' && c!=EOF) c=suck();
  499. X            break;
  500. X        }
  501. X        if (isspace(c) && !doingword) {
  502. X            startline=0;
  503. X            switch (c) {
  504. X            case ' ':
  505. X                assyline[assylen++]=' ';
  506. X                break;
  507. X            case '\t':
  508. X                tabulate();
  509. X                break;
  510. X            case '\n':
  511. X                goto out;
  512. X            }
  513. X            c = suck();
  514. X            continue;
  515. X        }
  516. X        if (isspace(c) && doingword) {    /* WHITE SPACE - FLUSH WORD */
  517. X            bumpword();
  518. X            if (c=='\t') tabulate();
  519. X            else if (assylen) assyline[assylen++]=' ';
  520. X            doingword=0;
  521. X            if (c=='\n') break;
  522. X        }
  523. X        if (!isspace(c)) {
  524. X/*
  525. X *    It's not a space.  If we're doing a word, continue it.
  526. X *    If it's a request, process it.
  527. X */
  528. X            if (doingword) *holdp++ = o_ul? c|UNDERL: c;
  529. X            else if (startline && c==o_cc && !o_li) {
  530. X                isrequest=1;
  531. X                return readreq();
  532. X            }
  533. X/*
  534. X *    It's the start of a new word.  Store it.
  535. X */
  536. X            else {
  537. X                doingword=1;
  538. X                holdp=holdword;
  539. X                *holdp++ = o_ul? c|UNDERL: c;
  540. X            }
  541. X        }
  542. X        startline=0;
  543. X        c = suck();
  544. X    }
  545. out:
  546. X    if (o_ul) o_ul--;
  547. X    if (o_li) o_li--;
  548. X    return c!=EOF;
  549. X}
  550. X
  551. X/*
  552. X *    bumpword - add word to current line.
  553. X */
  554. X
  555. bumpword()
  556. X{
  557. X    char *hc;
  558. X    *holdp = '\0';
  559. X/*
  560. X *    Tutelman's fix #1, modified by the Colonel.
  561. X */
  562. X    if (!o_fi || o_ce) goto giveup;
  563. X/*
  564. X *    We use a while-loop in case of ridiculously long words with
  565. X *    multiple hyphenation indicators.
  566. X */
  567. X    if (assylen + reallen(holdword) > o_ll - IDTLEN) {
  568. X        if (!o_hy) writeline(o_ad,0);
  569. X        else while (assylen + reallen(holdword) > o_ll - IDTLEN) {
  570. X/*
  571. X *    Try hyphenating it.
  572. X */
  573. X            if (o_hc && strhas(holdword,o_hc)) {
  574. X/*
  575. X *    There are hyphenation marks.  Use them!
  576. X */
  577. X                for (hc=strend(holdword); hc>=holdword; hc--) {
  578. X                    if ((*hc&~UNDERL)!=o_hc) continue;
  579. X                    *hc = '\0';
  580. X                    if (assylen + reallen(holdword) + 1 >
  581. X                    o_ll - IDTLEN) {
  582. X                        *hc = o_hc;
  583. X                        continue;
  584. X                    }
  585. X/*
  586. X *    Yay - it fits!
  587. X */
  588. X                    dehyph(holdword);
  589. X                    strcpy(&assyline[assylen],holdword);
  590. X                    strcat(assyline,"-");
  591. X                    assylen += strlen(holdword) + 1;
  592. X                    strcpy(holdword,++hc);
  593. X                    break;    /* STOP LOOKING */
  594. X                } /* for */
  595. X/*
  596. X *    It won't fit, or we've succeeded in breaking the word.
  597. X */
  598. X                writeline(o_ad,0);
  599. X                if (hc<holdword) goto giveup;
  600. X            }
  601. X            else {
  602. X/*
  603. X *    If no hyphenation marks, give up.
  604. X *    Let somebody else implement it.
  605. X */
  606. X                writeline(o_ad,0);
  607. X                goto giveup;
  608. X            }
  609. X        } /* while */
  610. X    }
  611. giveup:
  612. X/*
  613. X *    remove hyphenation marks, even if hyphenation is disabled.
  614. X */
  615. X    if (o_hc) dehyph(holdword);
  616. X    strcpy(&assyline[assylen],holdword);
  617. X    assylen+=strlen(holdword);
  618. X    holdp = holdword;
  619. X}
  620. X
  621. X/*
  622. X *    dehyph - remove hyphenation marks.
  623. X */
  624. X
  625. dehyph(s)
  626. char *s;
  627. X{
  628. X    char *t;
  629. X    for (t=s; *s; s++) if ((*s&~UNDERL) != o_hc) *t++ = *s;
  630. X    *t='\0';
  631. X}
  632. X
  633. X/*
  634. X *    reallen - length of a word, excluding hyphenation marks.
  635. X */
  636. X
  637. int
  638. reallen(s)
  639. char *s;
  640. X{
  641. X    register n;
  642. X    n=0;
  643. X    while (*s) n += (o_hc != (~UNDERL & *s++));
  644. X    return n;
  645. X}
  646. X
  647. tabulate()
  648. X{
  649. X    int j;
  650. X    for (j=0; j<n_ta; j++) if (o_ta[j]-1>assylen+IDTLEN) {
  651. X        for (; assylen+IDTLEN<o_ta[j]-1; assylen++)
  652. X            assyline[assylen]=o_tc;
  653. X        return;
  654. X    }
  655. X    /* NO TAB STOPS REMAIN */
  656. X    assyline[assylen++]=o_tc;
  657. X}
  658. X
  659. int
  660. readreq()
  661. X{
  662. X    char req[3];
  663. X    int r, s;
  664. X    if (skipsp()) return c!=EOF;
  665. X    c=suck();
  666. X    if (c==EOF || c=='\n') return c!=EOF;
  667. X    if (c=='.') {
  668. X        o_ig = 0;
  669. X        do (c=suck());
  670. X        while (c!=EOF && c!='\n');
  671. X        if (depth) endmac();
  672. X        return c!=EOF;
  673. X    }
  674. X    if (o_ig) {
  675. X        while (c!=EOF && c!='\n') c=suck();
  676. X        return c!=EOF;
  677. X    }
  678. X    req[0]=c;
  679. X    c=suck();
  680. X    if (c==EOF || c=='\n') req[1]='\0';
  681. X    else req[1]=c;
  682. X    req[2]='\0';
  683. X    for (r=0; r<n_macros; r++) if (!strcmp(macro[r].mname,req)) {
  684. X/*
  685. X *    It's a macro.  Invoke it.
  686. X */
  687. X        submac(r);
  688. X        goto reqflsh;
  689. X    }
  690. X    for (r=0; request[r]; r++) if (!strcmp(request[r],req)) break;
  691. X    if (!request[r]) {
  692. X/*
  693. X *    Invalid request.  Ignore it.
  694. X */
  695. X        do (c=suck());
  696. X        while (c!=EOF && c!='\n');
  697. X        return c!=EOF;
  698. X    }
  699. X    switch (r) {
  700. X    case 0: /* ad */
  701. X        o_ad=1;
  702. X        writebreak();
  703. X        break;
  704. X    case 1: /* ar */
  705. X        o_ro=0;
  706. X        break;
  707. X    case 2: /* bl */
  708. X        nread(&o_bl);
  709. X        writebreak();
  710. X        break;
  711. X    case 3: /* bp */
  712. X    case 37: /* pa */
  713. X        c=snread(&r,&s,1);
  714. X/*
  715. X *    Tutelman's fix #2 - the signs were reversed!
  716. X */
  717. X        if (s>0) o_bp=page_no+r;
  718. X        else if (s<0) o_bp=page_no-r;
  719. X        else o_bp=r;
  720. X        writebreak();
  721. X        if (line_no) {
  722. X            endpage();
  723. X            beginpage();
  724. X        }
  725. X        break;
  726. X    case 4: /* br */
  727. X        writebreak();
  728. X        break;
  729. X    case 5: /* cc */
  730. X        c=cread(&o_cc);
  731. X        break;
  732. X    case 6: /* ce */
  733. X/*
  734. X *    Fix to centering.  Set counter _after_ breaking!  --G.L.S.
  735. X */
  736. X        nread(&r);
  737. X        writebreak();
  738. X        o_ce = r;
  739. X        break;
  740. X    case 7: /* de */
  741. X        defmac();
  742. X        break;
  743. X    case 8: /* ds */
  744. X        o_ls=2;
  745. X        writebreak();
  746. X        break;
  747. X    case 9: /* ef */
  748. X        c=tread(efoot);
  749. X        break;
  750. X    case 10: /* eh */
  751. X        c=tread(ehead);
  752. X        break;
  753. X    case 11: /* fi */
  754. X        o_fi=1;
  755. X        writebreak();
  756. X        break;
  757. X    case 12: /* fo */
  758. X        c=tread(efoot);
  759. X        strcpy(ofoot,efoot);
  760. X        break;
  761. X    case 13: /* hc */
  762. X        c=cread(&o_hc);
  763. X        break;
  764. X    case 14: /* he */
  765. X        c=tread(ehead);
  766. X        strcpy(ohead,ehead);
  767. X        break;
  768. X    case 15: /* hx */
  769. X        o_hx=1;
  770. X        break;
  771. X    case 16: /* hy */
  772. X        nread(&o_hy);
  773. X        break;
  774. X    case 17: /* ig */
  775. X        o_ig=1;
  776. X        break;
  777. X    case 18: /* in */
  778. X        writebreak();
  779. X        snset(&o_in);
  780. X        o_ix = -1;
  781. X        break;
  782. X    case 19: /* ix */
  783. X        snset(&o_ix);
  784. X        if (!n_outwords) o_in=o_ix;
  785. X        break;
  786. X    case 20: /* li */
  787. X        nread(&o_li);
  788. X        break;
  789. X    case 21: /* ll */
  790. X        snset(&o_ll);
  791. X        break;
  792. X    case 22: /* ls */
  793. X        snset(&o_ls);
  794. X        break;
  795. X    case 23: /* m1 */
  796. X        nread(&o_m1);
  797. X        break;
  798. X    case 24: /* m2 */
  799. X        nread(&o_m2);
  800. X        break;
  801. X    case 25: /* m3 */
  802. X        nread(&o_m3);
  803. X        break;
  804. X    case 26: /* m4 */
  805. X        nread(&o_m4);
  806. X        break;
  807. X    case 27: /* n1 */
  808. X        o_n1=1;
  809. X        break;
  810. X    case 28: /* n2 */
  811. X        nread(&o_n2);
  812. X        break;
  813. X    case 29: /* na */
  814. X        o_ad=0;
  815. X        writebreak();
  816. X        break;
  817. X    case 30: /* ne */
  818. X        nread(&r);
  819. X        if (line_no+(r-1)*o_ls+1 > TXTLEN) {
  820. X            writebreak();
  821. X            endpage();
  822. X            beginpage();
  823. X        }
  824. X        break;
  825. X    case 31: /* nf */
  826. X        o_fi=0;
  827. X        writebreak();
  828. X        break;
  829. X    case 32: /* ni */
  830. X        snset(&o_ni);
  831. X        break;
  832. X    case 33: /* nn */
  833. X        snset(&o_nn);
  834. X        break;
  835. X    case 34: /* nx */
  836. X        do_nx();
  837. X        c='\n';    /* SO WE DON'T FLUSH THE FIRST LINE */
  838. X        break;
  839. X    case 35: /* of */
  840. X        c=tread(ofoot);
  841. X        break;
  842. X    case 36: /* oh */
  843. X        c=tread(ohead);
  844. X        break;
  845. X    case 38: /* pl */
  846. X        snset(&o_pl);
  847. X        break;
  848. X    case 39: /* po */
  849. X        snset(&o_po);
  850. X        break;
  851. X    case 40: /* ro */
  852. X        o_ro=1;
  853. X        break;
  854. X    case 41: /* sk */
  855. X        nread(&o_sk);
  856. X        break;
  857. X    case 42: /* sp */
  858. X        nread(&o_sp);
  859. X        writebreak();
  860. X        break;
  861. X    case 43: /* ss */
  862. X        writebreak();
  863. X        o_ls=1;
  864. X        break;
  865. X    case 44: /* ta */
  866. X        do_ta();
  867. X        break;
  868. X    case 45: /* tc */
  869. X        c=cread(&o_tc);
  870. X        break;
  871. X    case 46: /* ti */
  872. X        writebreak();
  873. X        c=snread(&r,&s,0);
  874. X        if (s>0) o_ti=o_in+r;
  875. X        else if (s<0) o_ti=o_in-r;
  876. X        else o_ti=r;
  877. X        break;
  878. X    case 47: /* tr */
  879. X        do_tr();
  880. X        break;
  881. X    case 48: /* ul */
  882. X        nread(&o_ul);
  883. X        break;
  884. X    }
  885. reqflsh:
  886. X    while (c!=EOF && c!='\n') c=suck();
  887. X    return c!=EOF;
  888. X}
  889. X
  890. X/*
  891. X *    snset - set a value upwards, downwards, or absolutely.
  892. X */
  893. X
  894. snset(par)
  895. int *par;
  896. X{
  897. X    int r, s;
  898. X    c=snread(&r,&s,0);
  899. X    if (s>0) *par+=r;
  900. X    else if (s<0) *par-=r;
  901. X    else *par=r;
  902. X}
  903. X
  904. tread(s)
  905. char *s;
  906. X{
  907. X    int leadbl;
  908. X    leadbl=0;
  909. X    for (;;) {
  910. X        c=suck();
  911. X        if (c==' ' && !leadbl) continue;
  912. X        if (c==EOF || c=='\n') {
  913. X            *s = '\0';
  914. X            return c;
  915. X        }
  916. X        *s++ = c;
  917. X        leadbl++;
  918. X    }
  919. X}
  920. X
  921. nread(i)
  922. int *i;
  923. X{
  924. X    int f;
  925. X    f=0;
  926. X    *i=0;
  927. X    if (!skipsp()) for (;;) {
  928. X        c=suck();
  929. X        if (c==EOF) break;
  930. X        if (isspace(c)) break;
  931. X        if (isdigit(c)) {
  932. X            f++;
  933. X            *i = *i*10 + c - '0';
  934. X        }
  935. X        else break;
  936. X    }
  937. X    if (!f) *i=1;
  938. X}
  939. X
  940. int
  941. snread(i,s,sdef)
  942. int *i, *s, sdef;
  943. X{
  944. X    int f;
  945. X    f = *i = *s = 0;
  946. X    for (;;) {
  947. X        c=suck();
  948. X        if (c==EOF || c=='\n') break;
  949. X        if (isspace(c)) {
  950. X            if (f) break;
  951. X            else continue;
  952. X        }
  953. X        if (isdigit(c)) {
  954. X            f++;
  955. X            *i = *i*10 + c - '0';
  956. X        }
  957. X        else if ((c=='+' || c=='-') && !f) {
  958. X            f++;
  959. X            *s = c=='+' ? 1 : -1;
  960. X        }
  961. X        else break;
  962. X    }
  963. X    while (c!=EOF && c!='\n') c=suck();
  964. X    if (!f) {
  965. X        *i=1;
  966. X        *s=sdef;
  967. X    }
  968. X    return c;
  969. X}
  970. X
  971. int
  972. cread(k)
  973. int *k;
  974. X{
  975. X    int u;
  976. X    *k = -1;
  977. X    for (;;) {
  978. X        u=suck();
  979. X        if (u==EOF || u=='\n') return u;
  980. X        if (isspace(u)) continue;
  981. X        if (*k < 0) *k=u;
  982. X    }
  983. X}
  984. X
  985. X/*
  986. X *    defmac - define a macro.
  987. X */
  988. X
  989. defmac()
  990. X{
  991. X    int i;
  992. X    char newmac[3], *nm;
  993. X    if (skipsp()) return;
  994. X    nm=newmac;
  995. X    if (!Macwrite) openmac();
  996. X    *nm++ = suck();
  997. X    c=suck();
  998. X    if (c!=EOF && c!='\n' && c!=' ' && c!='\t') *nm++ = c;
  999. X    *nm = '\0';
  1000. X        /* KILL OLD DEFINITION IF ANY */
  1001. X    for (i=0; i<n_macros; i++) if (!strcmp(newmac,macro[i].mname)) {
  1002. X        macro[i].mname[0]='\0';
  1003. X        break;
  1004. X    }
  1005. X    macro[n_macros].moff=ftell(Macwrite);
  1006. X    strcpy(macro[n_macros++].mname,newmac);    /* OVERFLOW HAZARD HERE! */
  1007. X    while (c!=EOF && c!='\n') c=suck();    /* FLUSH HEADER LINE */
  1008. X    while (copyline());
  1009. X    fflush(Macwrite);
  1010. X}
  1011. X
  1012. openmac()
  1013. X{
  1014. X    if (NULL==(Macwrite=fopen(mktemp(mfilnam),"w"))) {
  1015. X        fprintf(stderr,"roff: cannot open temp file\n");
  1016. X        exit(1);
  1017. X    }
  1018. X    Macread=fopen(mfilnam,"r");
  1019. X    unlink(mfilnam);
  1020. X}
  1021. X
  1022. int
  1023. copyline()
  1024. X{
  1025. X    int n, first, second;
  1026. X    if (c==EOF) {
  1027. X        fprintf(Macwrite,"..\n");
  1028. X        return 0;
  1029. X    }
  1030. X    n=0;
  1031. X    first=1;
  1032. X    second=0;
  1033. X    for (;;) {
  1034. X        c=suck();
  1035. X        if (c==EOF) {
  1036. X            if (!first) putc('\n',Macwrite);
  1037. X            return 0;
  1038. X        }
  1039. X        if (c=='\n') {
  1040. X            putc('\n',Macwrite);
  1041. X            return n!=2;
  1042. X        }
  1043. X        if (first && c=='.') n++;
  1044. X        else if (second && n==1 && c=='.') n++;
  1045. X        putc(c,Macwrite);
  1046. X        second=first;
  1047. X        first=0;
  1048. X    }
  1049. X}
  1050. X
  1051. submac(r)
  1052. int r;
  1053. X{
  1054. X    while (c!=EOF && c!='\n') c=suck();
  1055. X    if (depth) teller[depth-1]=ftell(Macread);
  1056. X    else {
  1057. X        Save = File;
  1058. X        File = Macread;
  1059. X    }
  1060. X    depth++;
  1061. X    fseek(Macread,macro[r].moff,0);
  1062. X}
  1063. X
  1064. endmac()
  1065. X{
  1066. X    depth--;
  1067. X    if (depth) fseek(Macread,teller[depth-1],0);
  1068. X    else File = Save;
  1069. X    c='\n';
  1070. X}
  1071. X
  1072. do_ta()
  1073. X{
  1074. X    int v;
  1075. X    n_ta = 0;
  1076. X    for (;;) {
  1077. X        nread(&v);
  1078. X        if (v==1) return;
  1079. X        else o_ta[n_ta++]=v;
  1080. X        if (c=='\n' || c==EOF) break;
  1081. X    }
  1082. X}
  1083. X
  1084. do_tr()
  1085. X{
  1086. X    char *t;
  1087. X    t = &o_tr[0][0];
  1088. X    *t='\0';
  1089. X    if (skipsp()) return;
  1090. X    for (;;) {
  1091. X        c=suck();
  1092. X        if (c==EOF || c=='\n') break;
  1093. X        *t++ = c;
  1094. X    }
  1095. X    *t = '\0';
  1096. X}
  1097. X
  1098. do_nx()
  1099. X{
  1100. X    char fname[100], *f;
  1101. X    f=fname;
  1102. X    if (skipsp()) return;
  1103. X    for (;;) switch(c=suck()) {
  1104. X    case EOF:
  1105. X    case '\n':
  1106. X    case ' ':
  1107. X    case '\t':
  1108. X        if (f==fname) return;
  1109. X        goto got_nx;
  1110. X    default:
  1111. X        *f++ = c;
  1112. X    }
  1113. got_nx:
  1114. X    fclose(File);
  1115. X    *f = '\0';
  1116. X    if (!(File=fopen(fname,"r"))) {
  1117. X        fprintf(stderr,"roff: cannot read %s\n",fname);
  1118. X        exit(1);
  1119. X    }
  1120. X}
  1121. X
  1122. int
  1123. skipsp()
  1124. X{
  1125. X    for (;;) switch(c=suck()) {
  1126. X    case EOF:
  1127. X    case '\n':
  1128. X        return 1;
  1129. X    case ' ':
  1130. X    case '\t':
  1131. X        continue;
  1132. X    default:
  1133. X        ungetc(c,File);
  1134. X        return 0;
  1135. X    }
  1136. X}
  1137. X
  1138. writebreak()
  1139. X{
  1140. X    int q;
  1141. X    if (assylen) writeline(0,1);
  1142. X    q = TXTLEN;
  1143. X    if (o_bl) {
  1144. X        if (o_bl + line_no > q) {
  1145. X            endpage();
  1146. X            beginpage();
  1147. X        }
  1148. X        for (; o_bl; o_bl--) blankline();
  1149. X    }
  1150. X    else if (o_sp) {
  1151. X        if (o_sp + line_no > q) newpage();
  1152. X        else if (line_no) for (; o_sp; o_sp--) blankline();
  1153. X    }
  1154. X}
  1155. X
  1156. blankline()
  1157. X{
  1158. X    if (line_no >= TXTLEN) newpage();
  1159. X    if (o_n2) o_n2++;
  1160. X    spit('\n');
  1161. X    line_no++;
  1162. X}
  1163. X
  1164. writeline(adflag,flushflag)
  1165. int adflag, flushflag;
  1166. X{
  1167. X    int j, q;
  1168. X    char lnstring[7];
  1169. X    for (j=assylen-1; j; j--) {
  1170. X        if (assyline[j]==' ') assylen--;
  1171. X        else break;
  1172. X    }
  1173. X    q = TXTLEN;
  1174. X    if (line_no >= q) newpage();
  1175. X    for (j=0; j<o_po; j++) spit(' ');
  1176. X    if (o_n1) {
  1177. X        if (o_nn) for (j=0; j<o_ni+4; j++) spit(' ');
  1178. X        else {
  1179. X            for (j=0; j<o_ni; j++) spit(' ');
  1180. X            sprintf(lnstring,"%3d ",line_no+1);
  1181. X            spits(lnstring);
  1182. X        }
  1183. X    }
  1184. X    if (o_n2) {
  1185. X        if (o_nn) for (j=0; j<o_ni+4; j++) spit(' ');
  1186. X        else {
  1187. X            for (j=0; j<o_ni; j++) spit(' ');
  1188. X            sprintf(lnstring,"%3d ",o_n2++);
  1189. X            spits(lnstring);
  1190. X        }
  1191. X    }
  1192. X    if (o_nn) o_nn--;
  1193. X    if (o_ce) for (j=0; j<(o_ll-assylen+1)/2; j++) spit(' ');
  1194. X    else for (j=0; j<IDTLEN; j++) spit(' ');
  1195. X    if (adflag && !flushflag) fillline();
  1196. X    for (j=0; j<assylen; j++) spit(assyline[j]);
  1197. X    spit('\n');
  1198. X    assylen=0;
  1199. X    assyline[0]='\0';
  1200. X    line_no++;
  1201. X    for (j=1; j<o_ls; j++) if (line_no <= q) blankline();
  1202. X    if (!flushflag)  {
  1203. X        if (o_hc) dehyph(holdword);
  1204. X        strcpy(assyline,holdword);
  1205. X        assylen=strlen(holdword);
  1206. X        *holdword='\0';
  1207. X        holdp=holdword;
  1208. X    }
  1209. X    if (o_ix>=0) o_in=o_ix;
  1210. X    o_ix = o_ti = -1;
  1211. X}
  1212. X
  1213. fillline()
  1214. X{
  1215. X    int excess, j, s, inc, spaces;
  1216. X    adjtoggle^=1;
  1217. X    if (!(excess = o_ll - IDTLEN - assylen)) return;
  1218. X    if (excess < 0) {
  1219. X        fprintf(stderr,"roff: internal error #2 [%d]\n",excess);
  1220. X        exit(1);
  1221. X    }
  1222. X    for (j=2;; j++) {
  1223. X        if (adjtoggle) {
  1224. X            s=0;
  1225. X            inc = 1;
  1226. X        }
  1227. X        else {
  1228. X            s=assylen-1;
  1229. X            inc = -1;
  1230. X        }
  1231. X        spaces=0;
  1232. X        while (s>=0 && s<assylen) {
  1233. X            if (assyline[s]==' ') spaces++;
  1234. X            else {
  1235. X                if (0<spaces && spaces<j) {
  1236. X                    insrt(s-inc);
  1237. X                    if (inc>0) s++;
  1238. X                    if (!--excess) return;
  1239. X                }
  1240. X                spaces=0;
  1241. X            }
  1242. X            s+=inc;
  1243. X        }
  1244. X    }
  1245. X}
  1246. X
  1247. insrt(p)
  1248. int p;
  1249. X{
  1250. X    int i;
  1251. X    for (i=assylen; i>p; i--) assyline[i]=assyline[i-1];
  1252. X    assylen++;
  1253. X}
  1254. X
  1255. newpage()
  1256. X{
  1257. X    if (page_no >= 0) endpage();
  1258. X    else page_no=1;
  1259. X    for (; o_sk; o_sk--) blankpage();
  1260. X    beginpage();
  1261. X}
  1262. X
  1263. beginpage()
  1264. X{
  1265. X    int i;
  1266. X    if (sflag) waitawhile();
  1267. X    for (i=0; i<o_m1; i++) spit('\n');
  1268. X    writetitle(page_no&1? ohead: ehead);
  1269. X    for (i=0; i<o_m2; i++) spit('\n');
  1270. X    line_no=0;
  1271. X}
  1272. X
  1273. endpage()
  1274. X{
  1275. X    int i;
  1276. X    for (i=line_no; i<TXTLEN; i++) blankline();
  1277. X    for (i=0; i<o_m3; i++) spit('\n');
  1278. X    writetitle(page_no&1? ofoot: efoot);
  1279. X    for (i=0; i<o_m4; i++) spit('\n');
  1280. X    if (o_bp < 0) page_no++;
  1281. X    else {
  1282. X        page_no = o_bp;
  1283. X        o_bp = -1;
  1284. X    }
  1285. X}
  1286. X
  1287. blankpage()
  1288. X{
  1289. X    int i;
  1290. X    if (sflag) waitawhile();
  1291. X    for (i=0; i<o_m1; i++) spit('\n');
  1292. X    writetitle(page_no&1? ohead: ehead);
  1293. X    for (i=0; i<o_m2; i++) spit('\n');
  1294. X    for (i=0; i<TXTLEN; i++) spit('\n');
  1295. X    for (i=0; i<o_m3; i++) spit('\n');
  1296. X    writetitle(page_no&1? ofoot: efoot);
  1297. X    page_no++;
  1298. X    for (i=0; i<o_m4; i++) spit('\n');
  1299. X    line_no=0;
  1300. X}
  1301. X
  1302. waitawhile()
  1303. X{
  1304. X    int nix(), oldflags;
  1305. X    if (isatty(0)) {
  1306. X        oldflags=tty.sg_flags;
  1307. X        tty.sg_flags &= ~ECHO;    /* DON'T ECHO THE RUBOUT */
  1308. X        stty(0,&tty);
  1309. X    }
  1310. X    signal(SIGINT,nix);
  1311. X    pause();
  1312. X    if (isatty(0)) {
  1313. X        tty.sg_flags = oldflags;
  1314. X        stty(0,&tty);
  1315. X    }
  1316. X}
  1317. X
  1318. nix()
  1319. X{}
  1320. X
  1321. writetitle(t)
  1322. char *t;
  1323. X{
  1324. X    char d, *pst, *pgform();
  1325. X    int j, l, m, n;
  1326. X    d = *t;
  1327. X    if (o_hx || !d) {
  1328. X        spit('\n');
  1329. X        return;
  1330. X    }
  1331. X    pst=pgform();
  1332. X    for (j=0; j<o_po; j++) spit(' ');
  1333. X    l=titlen(++t,d,strlen(pst));
  1334. X    while (*t && *t!=d) {
  1335. X        if (*t=='%') spits(pst);
  1336. X        else spit(*t);
  1337. X        t++;
  1338. X    }
  1339. X    if (!*t) {
  1340. X        spit('\n');
  1341. X        return;
  1342. X    }
  1343. X    m=titlen(++t,d,strlen(pst));
  1344. X    for (j=l; j<(o_ll-m)/2; j++) spit(' ');
  1345. X    while (*t && *t!=d) {
  1346. X        if (*t=='%') spits(pst);
  1347. X        else spit(*t);
  1348. X        t++;
  1349. X    }
  1350. X    if (!*t) {
  1351. X        spit('\n');
  1352. X        return;
  1353. X    }
  1354. X    if ((o_ll-m)/2 > l) m+=(o_ll-m)/2;
  1355. X    else m+=l;
  1356. X    n=titlen(++t,d,strlen(pst));
  1357. X    for (j=m; j<o_ll-n; j++) spit(' ');
  1358. X    while (*t && *t!=d) {
  1359. X        if (*t=='%') spits(pst);
  1360. X        else spit(*t);
  1361. X        t++;
  1362. X    }
  1363. X    spit('\n');
  1364. X}
  1365. X
  1366. char *
  1367. pgform()
  1368. X{
  1369. X    static char pst[11];
  1370. X    int i;
  1371. X    if (o_ro) {
  1372. X        *pst='\0';
  1373. X        i=page_no;
  1374. X        if (i>=400) {
  1375. X            strcat(pst,"cd");
  1376. X            i-=400;
  1377. X        }
  1378. X        while (i>=100) {
  1379. X            strcat(pst,"c");
  1380. X            i-=100;
  1381. X        }
  1382. X        if (i>=90) {
  1383. X            strcat(pst,"xc");
  1384. X            i-=90;
  1385. X        }
  1386. X        if (i>=50) {
  1387. X            strcat(pst,"l");
  1388. X            i-=50;
  1389. X        }
  1390. X        if (i>=40) {
  1391. X            strcat(pst,"xl");
  1392. X            i-=40;
  1393. X        }
  1394. X        while (i>=10) {
  1395. X            strcat(pst,"x");
  1396. X            i-=10;
  1397. X        }
  1398. X        if (i>=9) {
  1399. X            strcat(pst,"ix");
  1400. X            i-=9;
  1401. X        }
  1402. X        if (i>=5) {
  1403. X            strcat(pst,"v");
  1404. X            i-=5;
  1405. X        }
  1406. X        if (i>=4) {
  1407. X            strcat(pst,"iv");
  1408. X            i-=4;
  1409. X        }
  1410. X        while (i--) strcat(pst,"i");
  1411. X    }
  1412. X    else sprintf(pst,"%d",page_no);
  1413. X    return pst;
  1414. X}
  1415. X
  1416. int
  1417. titlen(t,c,k)
  1418. char *t, c;
  1419. int k;
  1420. X{
  1421. X    int q;
  1422. X    q=0;
  1423. X    while (*t && *t!=c) q += *t++ == '%' ? k : 1;
  1424. X    return q;
  1425. X}
  1426. X
  1427. spits(s)
  1428. char *s;
  1429. X{
  1430. X    while (*s) spit(*s++);
  1431. X}
  1432. X
  1433. spit(c)
  1434. char c;
  1435. X{
  1436. X    static int col_no, n_blanks;
  1437. X    int ulflag;
  1438. X    char *t;
  1439. X    ulflag=c&UNDERL;
  1440. X    c&=~UNDERL;
  1441. X    for (t = (char *)o_tr; *t; t++) if (*t++==c) {
  1442. X/*
  1443. X *    fix - last char translates to space.
  1444. X */
  1445. X        c = *t? *t: ' ';
  1446. X        break;
  1447. X    }
  1448. X    if (page_no < startpage || (stoppage && page_no > stoppage)) return;
  1449. X    if (c != ' ' && c != '\n' && n_blanks) {
  1450. X        if (hflag && n_blanks>1)
  1451. X        while (col_no/8 < (col_no+n_blanks)/8) {
  1452. X            putc('\t',stdout);
  1453. X            n_blanks-= 8 - (col_no & 07);
  1454. X            col_no = 8 + col_no & ~07;
  1455. X        }
  1456. X        for (; n_blanks; n_blanks--) {
  1457. X            putc(' ',stdout);
  1458. X            col_no++;
  1459. X        }
  1460. X    }
  1461. X    if (ulflag && isalnum(c)) fputs("_\b",stdout);
  1462. X    if (c == ' ') n_blanks++;
  1463. X    else {
  1464. X        putc(c,stdout);
  1465. X        col_no++;
  1466. X    }
  1467. X    if (c == '\n') {
  1468. X        col_no=0;
  1469. X        n_blanks=0;
  1470. X    }
  1471. X}
  1472. X
  1473. int
  1474. suck()
  1475. X{
  1476. X    for (;;) {
  1477. X        c=getc(File);
  1478. X        if (islegal(c)) return c;
  1479. X    }
  1480. X}
  1481. X
  1482. X/*
  1483. X *    strhas - does string have character?  Allow UNDERL flag.
  1484. X */
  1485. X
  1486. char *
  1487. strhas(p,c)
  1488. char *p, c;
  1489. X{
  1490. X    for (; *p; p++) if ((*p&~UNDERL)==c) return p;
  1491. X    return NULL;
  1492. X}
  1493. X
  1494. X/*
  1495. X *    strend - find NULL at end of string.
  1496. X */
  1497. X
  1498. char *
  1499. strend(p)
  1500. char *p;
  1501. X{
  1502. X    while (*p++);
  1503. X    return p;
  1504. X}
  1505. X
  1506. X/*
  1507. X *    isspace, isalnum, isdigit, islegal - classify a character.
  1508. X *    We could just as well use <ctype.h> if it didn't vary from
  1509. X *    one version of Unix to another.  As it is, these routines
  1510. X *    must be modified for weird character sets, like EBCDIC and
  1511. X *    CDC Scientific.
  1512. X */
  1513. X
  1514. int
  1515. isspace(c)
  1516. int c;
  1517. X{
  1518. X    char *s;
  1519. X    for (s=spacechars; *s; s++) if (*s==c) return 1;
  1520. X    return 0;
  1521. X}
  1522. X
  1523. int
  1524. isalnum(c)
  1525. int c;
  1526. X{
  1527. X    return (c>='A'&&c<='Z') || (c>='a'&&c<='z') || (c>='0'&&c<='9');
  1528. X}
  1529. X
  1530. int
  1531. isdigit(c)
  1532. int c;
  1533. X{
  1534. X    return c>='0' && c<='9';
  1535. X}
  1536. X
  1537. int
  1538. islegal(c)
  1539. int c;
  1540. X{
  1541. X    return c>=' ' && c<='~' || isspace(c) || c=='\n' || c==EOF;
  1542. X}
  1543. X
  1544. bomb()
  1545. X{
  1546. X    fprintf(stderr,"usage: roff [+00] [-00] [-s] [-h] file ...\n");
  1547. X    exit(1);
  1548. X}
  1549. END_OF_FILE
  1550. if test 20604 -ne `wc -c <'roff.c'`; then
  1551.     echo shar: \"'roff.c'\" unpacked with wrong size!
  1552. fi
  1553. # end of 'roff.c'
  1554. fi
  1555. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1556.   echo shar: Will not clobber existing file \"'Makefile'\"
  1557. else
  1558. echo shar: Extracting \"'Makefile'\" \(384 characters\)
  1559. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1560. DESTROOT=
  1561. DESTPATH=$(DESTROOT)/usr/local
  1562. BIN=$(DESTPATH)/bin
  1563. MAN=$(DESTPATH)/man
  1564. CFLAGS= -O
  1565. X
  1566. all: roff
  1567. X
  1568. roff: roff.o
  1569. X    cc -o roff roff.o
  1570. X
  1571. install: roff roff.1
  1572. X    (echo ".ds Bd $(BIN)"; cat roff.1) > $(MAN)/man1/roff.1
  1573. X    -rm -f $(BIN)/roff
  1574. X    -cp roff $(BIN)/roff
  1575. X
  1576. shar: roff.shar
  1577. X
  1578. roff.shar: Makefile roff.1 roff.c
  1579. X    shar Makefile roff.1 roff.c > roff.shar
  1580. X
  1581. clean:
  1582. X    rm -f *.o roff roff.shar
  1583. END_OF_FILE
  1584. if test 384 -ne `wc -c <'Makefile'`; then
  1585.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1586. fi
  1587. # end of 'Makefile'
  1588. fi
  1589. echo shar: End of shell archive.
  1590. exit 0
  1591.